package com.atguigu.lease.web.admin.service.impl;

import com.atguigu.lease.common.exception.LeaseException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import com.atguigu.lease.model.entity.*;
import com.atguigu.lease.model.enums.ItemType;
import com.atguigu.lease.model.enums.ReleaseStatus;
import com.atguigu.lease.web.admin.mapper.ApartmentInfoMapper;
import com.atguigu.lease.web.admin.service.*;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentDetailVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentItemVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentQueryVo;
import com.atguigu.lease.web.admin.vo.apartment.ApartmentSubmitVo;
import com.atguigu.lease.web.admin.vo.fee.FeeValueVo;
import com.atguigu.lease.web.admin.vo.graph.GraphVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author liubo
 * @description 针对表【apartment_info(公寓信息表)】的数据库操作Service实现
 * @createDate 2023-07-24 15:48:00
 */
@Service
@Transactional
public class ApartmentInfoServiceImpl extends ServiceImpl<ApartmentInfoMapper, ApartmentInfo>
        implements ApartmentInfoService {
    @Autowired
    private ApartmentFacilityService apartmentFacilityService;
    @Autowired
    private ApartmentFeeValueService apartmentFeeValueService;
    @Autowired
    private ApartmentLabelService apartmentLabelService;
    @Autowired
    private GraphInfoService graphInfoService;
    @Autowired
    private ApartmentInfoMapper apartmentInfoMapper;
    @Autowired
    private LabelInfoService labelInfoService;
    @Autowired
    private FeeValueService feeValueService;
    @Autowired
    private RoomInfoService roomInfoService;
    @Override
    public void saveOrUpdateApartment(ApartmentSubmitVo apartmentSubmitVo) {
        Long apartmentId0 = apartmentSubmitVo.getId();
        boolean updateFlag = apartmentSubmitVo.getId() != null&& apartmentSubmitVo.getId() != 0;
        //1. 保存或更新ApartmentInfo自身的信息（insert,update）
        super.saveOrUpdate(apartmentSubmitVo);
        //2.如果是更新，需要删除之前的内容
        if (updateFlag){
            //2.1删除和配套的关系
           /* apartmentSubmitVo.getFacilityInfoIds().forEach(facilityId ->{
                apartmentFacilityService.remove(new LambdaQueryWrapper<ApartmentFacility>()
                        .eq(ApartmentFacility::getFacilityId,facilityId)
                        .eq(ApartmentFacility::getApartmentId,apartmentSubmitVo.getId()));
            });*/
            apartmentFacilityService.remove(new LambdaQueryWrapper<ApartmentFacility>()
                    .eq(ApartmentFacility::getApartmentId,apartmentId0));
            //2.2 删除和杂费关系
            apartmentFeeValueService.remove(new LambdaQueryWrapper<ApartmentFeeValue>()
                    .eq(ApartmentFeeValue::getApartmentId,apartmentId0));
            //2.3删除和标签的关系
            apartmentLabelService.remove(new LambdaQueryWrapper<ApartmentLabel>()
                    .eq(ApartmentLabel::getApartmentId,apartmentId0));
            //2.4删除和图片的关系
            graphInfoService.remove(new LambdaQueryWrapper<GraphInfo>()
                    .eq(GraphInfo::getItemType,ItemType.APARTMENT)
                    .eq(GraphInfo::getItemId,apartmentId0));

        }
        //3.保存公寓关系信息（和配套的关系，杂费，标签，图片的关系）
        //3.1 保存公寓配套信息
        //解释：apartmentSubmitVo.getFacilityInfoIds() 得到的是一个List<Long>集合，这个集合保存了facilityId
        //.stream() 变成流，进行流式计算
        //.map() 映射，将流中的每一个元素映射为另一个元素
      Long  apartmentId = apartmentSubmitVo.getId();
        apartmentSubmitVo.getFacilityInfoIds().stream().map(facilityId ->
             new ApartmentFacility(apartmentId, facilityId))
                .forEach(apartmentFacilityService::saveOrUpdate);
    //3-2. 保存公寓杂费信息
        apartmentSubmitVo.getFeeValueIds().stream().map(feeValueId ->
             new ApartmentFeeValue(apartmentId, feeValueId))
                .forEach(apartmentFeeValueService::saveOrUpdate);

    //3-3. 保存公寓标签信息
        apartmentSubmitVo.getLabelIds().stream().map(labelId ->
                ApartmentLabel.builder()
                        .apartmentId(apartmentId).labelId(labelId).build())
                .forEach(apartmentLabelService::saveOrUpdate);

    //3-4. 保存公寓图片信息
        List<GraphInfo> graphInfoList = new ArrayList<>();

        apartmentSubmitVo.getGraphVoList().forEach(graphVo ->{
            GraphInfo graphInfo = new GraphInfo();
            BeanUtils.copyProperties(graphVo,graphInfo);
            graphInfo.setItemType(ItemType.APARTMENT);
            graphInfo.setItemId(apartmentId);
            graphInfoList.add(graphInfo);

        });
        graphInfoService.saveOrUpdateBatch(graphInfoList);

    }

    @Override
    public void pageApartmentItemByQuery(IPage<ApartmentItemVo> page, ApartmentQueryVo queryVo) {
       page =   apartmentInfoMapper.pageApartmentItemByQuery(page, queryVo);
    }

    @Override
    public ApartmentDetailVo getApartmentDetailById(Long apartmentId) {
        //业务方法：获取公寓详情
        //1.获取公寓的基本信息
        ApartmentInfo apartmentInfo = getById(apartmentId);
       if(apartmentInfo!=null) {
           //2.获取公寓的配套信息
           List<FacilityInfo> facilityInfoList = apartmentFacilityService.getApartmentFacilityListByApartmentId(apartmentId);
           //3.获取公寓的杂费信息
           List<FeeValueVo> feeValueVoList = feeValueService.getFeeValueListByApartmentId(apartmentId);
           //4.获取公寓的图片信息
           List<GraphInfo> graphInfoList = graphInfoService.list(new LambdaQueryWrapper<GraphInfo>()
                   .eq(GraphInfo::getItemType, ItemType.APARTMENT)
                   .eq(GraphInfo::getItemId, apartmentId));
           //5.获取公寓的标签信息
           List<LabelInfo> labelInfoList = labelInfoService.getApartmentLabelListByApartmentId(apartmentId);
           //6.封装数据到ApartmentDetailVo
           ApartmentDetailVo apartmentDetailVo = new ApartmentDetailVo();
           BeanUtils.copyProperties(apartmentInfo, apartmentDetailVo);
           apartmentDetailVo.setFacilityInfoList(facilityInfoList);
           apartmentDetailVo.setFeeValueVoList(feeValueVoList);
           apartmentDetailVo.setGraphVoList(graphInfoList
                   .stream()
                   .map(graphInfo -> GraphVo.builder()
                           .name(graphInfo.getName())
                           .url(graphInfo.getUrl())
                           .build()).collect(Collectors.toList()));
           apartmentDetailVo.setLabelInfoList(labelInfoList);
           return apartmentDetailVo;
       }
       return null;
    }

    @Override
    public void removeApartmentById(Long id) {
        //如果公寓有租客，不能删除 抛出异常 207
        if (roomInfoService.count(new LambdaQueryWrapper<RoomInfo>().eq(RoomInfo::getApartmentId,id))>0){
            //此处抛出异常，被全局异常所捕获
            throw new LeaseException(ResultCodeEnum.DELETE_ERROR);
        }
        //1删除公寓本身的信息
        super.removeById(id);
        //2删除这个公寓关联的信息：配套，杂费，标签，图片
        //2.1删除和配套的关系
        apartmentFacilityService.remove(new LambdaQueryWrapper<ApartmentFacility>()
                .eq(ApartmentFacility::getApartmentId,id));
        //2.2 删除和杂费关系
        apartmentFeeValueService.remove(new LambdaQueryWrapper<ApartmentFeeValue>()
                .eq(ApartmentFeeValue::getApartmentId,id));
        //2.3删除和标签的关系
        apartmentLabelService.remove(new LambdaQueryWrapper<ApartmentLabel>()
                .eq(ApartmentLabel::getApartmentId,id));
        //2.4删除和图片的关系
        graphInfoService.remove(new LambdaQueryWrapper<GraphInfo>()
                .eq(GraphInfo::getItemType,ItemType.APARTMENT)
                .eq(GraphInfo::getItemId,id));
    }

    @Override
    public void updateStatusById(Long id, ReleaseStatus status) {
        super.update(new LambdaUpdateWrapper<ApartmentInfo>()
                .eq(ApartmentInfo::getId,id)
                .set(ApartmentInfo::getIsRelease,status));
    }
}




